
/* <<< COPYRIGHT START >>>
 * Copyright 2006-Present OxygenSoftwareLibrary.com
 * Licensed under the GNU Lesser General Public License.
 * http://www.gnu.org/licenses/lgpl.html
 * 
 * @author: Ugorji Dick-Nwoke
 * <<< COPYRIGHT END >>>
 */


package oxygen.tool.wlfacade.helpers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ObjectName;

import oxygen.tool.wlfacade.WLFacadeContextHelper;
import oxygen.tool.wlfacade.WLJMXHandler;
import oxygen.tool.wlfacade.WLMBSTree;
import oxygen.tool.wlfacade.WLScriptHelper;
import oxygen.util.OxyTable;
import oxygen.util.StringUtils;
import weblogic.management.info.ExtendedAttributeInfo;

/**
 * Usage:
 * wllist -attributes ab cd ef gh ij 
 *   (shows names, and attributes)
 * wllist (only shows the names)
 */
public class WLList {

  public static OxyTable listtypes(WLFacadeContextHelper wlctx) throws Exception {
    return listtypes(wlctx, null);
  }
  
  public static OxyTable listtypes(WLFacadeContextHelper wlctx, Map matchMap) throws Exception {
    WLScriptHelper.ensureConnected(wlctx);
    WLScriptHelper.ensurePrimaryDomain(wlctx);
    WLScriptHelper.ensureMBSTree(wlctx);
    
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    ObjectName cmo = (ObjectName)wltree.pointer();
    WLJMXHandler dmhdlr = wltree.getJMXHandler();
    ObjectName pattern = new ObjectName(wltree.getDomain() + ":*");
    ObjectName[] ois = WLScriptHelper.getObjNames(wltree.getMBS(), pattern, dmhdlr, cmo, false, null);
    ois = WLScriptHelper.getSubsetForMatch(ois, matchMap);

    Set s = new HashSet();
    for(int i = 0; i < ois.length; i++) {
      s.add(ois[i].getKeyProperty("Type"));
    }
    String[] ss = (String[])s.toArray(new String[0]);
    Arrays.sort(ss);
    String[] headers = new String[]{"Types"};
    String[] row = new String[headers.length];
    OxyTable tabl = new OxyTable(headers);
    tabl.setInternalObject(ss);
    for(int i = 0; i < ss.length; i++) {
      row[0] = ss[i];
      tabl.addRow(row);
    }
    return tabl;    
  }
  
  public static OxyTable listroots(WLFacadeContextHelper wlctx, Map matchMap) throws Exception {
    WLScriptHelper.ensureConnected(wlctx);
    WLScriptHelper.ensureMBSTree(wlctx);
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    WLJMXHandler dmhdlr = wltree.getJMXHandler();
    //System.out.println("wltree.getDomain(): " + wltree.getDomain());
    ObjectName pattern = new ObjectName(wltree.getDomain() + ":*");
    ObjectName[] ois = WLScriptHelper.getObjNames(wltree.getMBS(), pattern, dmhdlr, null, true, null);
    ois = WLScriptHelper.getSubsetForMatch(ois, matchMap);
    return getOxyTable(wlctx, ois, wltree.getMBS(), true);
  }
  
  public static OxyTable listroots(WLFacadeContextHelper wlctx) throws Exception {
    return listroots(wlctx, null);
  }
  
  public static OxyTable list(WLFacadeContextHelper wlctx, Map wlm) throws Exception {
    WLScriptHelper.ensureMBSTree(wlctx);
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    ObjectName cmo = (ObjectName)wltree.pointer();
    return list(wlctx, cmo, wlm);
  }
  
  /**
   * e.g. list(wlctx, "Type", "Domain*")
   */
  public static OxyTable list(WLFacadeContextHelper wlctx, String pname, String pvalregex) throws Exception {
    WLScriptHelper.ensureMBSTree(wlctx);
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    ObjectName cmo = (ObjectName)wltree.pointer();
    Map wlm = new HashMap();
    wlm.put(pname, pvalregex);
    return list(wlctx, cmo, wlm);
  }
  
  public static OxyTable list(WLFacadeContextHelper wlctx) throws Exception {
    WLScriptHelper.ensureMBSTree(wlctx);
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    ObjectName cmo = (ObjectName)wltree.pointer();
    return list(wlctx, cmo, null);
  }
  
  public static OxyTable listdomains(WLFacadeContextHelper wlctx) throws Exception {
    WLScriptHelper.ensureConnected(wlctx);
    WLScriptHelper.ensureMBSTree(wlctx);
    
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    String[] domains = WLScriptHelper.getDomains(wltree.getMBS());
    Object mbs = wltree.getMBS();
    String[] headers = new String[]{"Domains", "Info"};
    Object[] row = new Object[headers.length];
    OxyTable tabl = new OxyTable(headers);
    tabl.setInternalObject(domains);
    for(int i = 0; i < domains.length; i++) {
      row[0] = domains[i];
      ArrayList al = new ArrayList();
      if(domains[i].equals(wltree.getDomain())) {
        al.add("CURRENT");
      }
      if(domains[i].equals(wlctx.getConnection().getDomainName())) {
        al.add("PRIMARY");
      }
      if(domains[i].equals(WLScriptHelper.mbs_getDefaultDomain(mbs))) {
        al.add("DEFAULT");
      }
      row[1] = al;
      tabl.addRow(row);
    }
    tabl.sort();
    return tabl;
  }

  public static OxyTable listtrees(WLFacadeContextHelper wlctx) throws Exception {
    Map trees = wlctx.getTrees();
    if(trees == null) {
      trees = new HashMap();
    }
    String[] headers = new String[]{"Key", "Tree"};
    Object[] row = new Object[headers.length];
    OxyTable tabl = new OxyTable(headers);

    for(Iterator itr = trees.keySet().iterator(); itr.hasNext(); ) {
      row[0] = itr.next();
      row[1] = trees.get(row[0]);
      tabl.addRow(row);
    }
    tabl.sort();
    return tabl;
  }
  
  public static OxyTable find(WLFacadeContextHelper wlctx, String stringrep) throws Exception {
    WLScriptHelper.ensureConnected(wlctx);
    WLScriptHelper.ensureMBSTree(wlctx);
    
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    WLJMXHandler dmhdlr = wltree.getJMXHandler();
    ObjectName pattern = dmhdlr.getLookupPattern(wltree.getDomain(), stringrep);
    //System.out.println(pattern);
    ObjectName[] ois = WLScriptHelper.getObjNames(wltree.getMBS(), pattern, dmhdlr, null, false, null);
    //System.out.println(Arrays.asList(ois));
    return getOxyTable(wlctx, ois, wltree.getMBS(), true);
  }
  
  private static OxyTable list(WLFacadeContextHelper wlctx, ObjectName cmo, Map matchMap) throws Exception {
    WLScriptHelper.ensureConnected(wlctx);
    WLScriptHelper.ensureMBSTree(wlctx);
    
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    WLJMXHandler dmhdlr = wltree.getJMXHandler();
    ObjectName pattern = new ObjectName(wltree.getDomain() + ":*");
    ObjectName[] ois = null;
    if(cmo == null) {
      ois = WLScriptHelper.getObjNames(wltree.getMBS(), pattern, dmhdlr, null, true, null);
    } else {
      ois = WLScriptHelper.getObjNames(wltree.getMBS(), pattern, dmhdlr, cmo, false, null);
    }
    ois = WLScriptHelper.getSubsetForMatch(ois, matchMap);
    //boolean isAbsolute = (cmo == null);
    return getOxyTable(wlctx, ois, wltree.getMBS(), false);
  }
  
  private static OxyTable getOxyTable(WLFacadeContextHelper wlctx, ObjectName[] ois, Object mbs, boolean isAbsolute) throws Exception {
    WLScriptHelper.ensureMBSTree(wlctx);
    String[] headers = new String[]{"Object Names"};
    String[] row = new String[headers.length];
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    WLJMXHandler dmhdlr = wltree.getJMXHandler();
    OxyTable tabl = new OxyTable(headers);
    tabl.setInternalObject(ois);
    for(int i = 0; i < ois.length; i++) {
      row[0] = dmhdlr.getStringRep(ois[i], mbs, isAbsolute);
      if(!isAbsolute && row[0].length() > 0 && row[0].startsWith("/")) {
        row[0] = row[0].substring(1);
      }
      tabl.addRow(row);
    }
    tabl.sort();
    return tabl;
    //tabl.printTo(new PrintWriter(System.out));
  }
  
  public static OxyTable listatts(WLFacadeContextHelper wlctx) throws Exception {
    return listatts(wlctx, null);
  }
  
  public static OxyTable listatts(WLFacadeContextHelper wlctx, String regex) throws Exception {
    WLScriptHelper.ensureConnected(wlctx);
    WLScriptHelper.ensureNotDomainRoot(wlctx);
    WLScriptHelper.ensureMBSTree(wlctx);
    
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    ObjectName cmo = (ObjectName)wltree.pointer();
    Object mbs = wltree.getMBS();
    MBeanInfo mbinfo = WLScriptHelper.mbs_getMBeanInfo(mbs, cmo);
    MBeanAttributeInfo[] attsinfo = mbinfo.getAttributes();    
    
    Map map = new HashMap();
    TreeSet al = new TreeSet();
    for(int i = 0; i < attsinfo.length; i++) {
      String attname = attsinfo[i].getName();
      al.add(attname);
      map.put(attname, attsinfo[i]);
    }
    
    String[] headers = new String[]{"", "Name", "Type", "Value"};
    OxyTable tabl = new OxyTable(headers);
    tabl.setDescription("Attributes: 1st column Legend: D=dynamic, C=configurable, *=encrypted, r=readable, w=writable");
    tabl.setMainIndex(1);
    tabl.setInternalObject(attsinfo);
    Object[] row = new Object[headers.length];
    String[] attnames = (String[])al.toArray(new String[0]);
    AttributeList attlist = WLScriptHelper.mbs_getAttributes(mbs, cmo, attnames);
    for(Iterator itr = attlist.iterator(); itr.hasNext(); ) {
      Attribute att = (Attribute)itr.next();
      MBeanAttributeInfo attinfo = (MBeanAttributeInfo)map.get(att.getName());    
      addAtt(att, attinfo, regex, tabl, row);
    }
    //tabl.printTo(new PrintWriter(System.out));
    tabl.sort();
    return tabl;
  }
  
  private static void addAtt(Attribute att, MBeanAttributeInfo attinfo,
                             String regex, OxyTable tabl, Object[] row) 
    throws Exception {
    String attname = att.getName();
    if(regex != null && !(StringUtils.matchSimpleRegex(attname, regex))) {
      return;
    }
    boolean isDynamic = false;
    boolean isConfigurable = false;
    boolean isExcluded = false;
    boolean isEncrypted = false;
    if(attinfo instanceof ExtendedAttributeInfo) {
      ExtendedAttributeInfo extattinfo = (ExtendedAttributeInfo)attinfo;
      isDynamic = extattinfo.isDynamic();
      isConfigurable = extattinfo.isConfigurable();
      isExcluded = extattinfo.isExcluded();
      isEncrypted = extattinfo.isEncrypted();
    }
    if(isExcluded) {
      return;
    }
    
    StringBuffer buf = new StringBuffer();
    //addAttAppend(buf, false, " ", " ");
    addAttAppend(buf, isDynamic, "D", "-");
    addAttAppend(buf, isConfigurable, "C", "-");
    //addAttAppend(buf, isExcluded, "E", "-");
    addAttAppend(buf, isEncrypted, "*", "-");
    addAttAppend(buf, false, " ", " ");
    //addAttAppend(buf, attinfo.isIs(), "i", "-");
    addAttAppend(buf, attinfo.isReadable(), "r", "-");
    addAttAppend(buf, attinfo.isWritable(), "w", "-");
    //addAttAppend(buf, false, " ", " ");

    row[0] = buf.toString();
    row[1] = attname;
    row[2] = attinfo.getType();
    Object value = att.getValue();
    if(value != null && value instanceof Object[]) {
      value = Arrays.asList((Object[])value).toString();
    }
    row[3] = value;
    tabl.addRow(row);
  }
  
  
  private static void addAttAppend(StringBuffer buf, boolean b, String s0, String s1) {
    if(b) {
      buf.append(s0);
    } else {
      buf.append(s1);
    }
  }
  
  public static OxyTable listops(WLFacadeContextHelper wlctx) throws Exception {
    return listops(wlctx, null);
  }
  
  public static OxyTable listops(WLFacadeContextHelper wlctx, String regex) throws Exception {
    WLScriptHelper.ensureConnected(wlctx);
    WLScriptHelper.ensureNotDomainRoot(wlctx);
    // name return-type argument
    WLScriptHelper.ensureMBSTree(wlctx);
    
    WLMBSTree wltree = (WLMBSTree)wlctx.getCurrentTree();
    ObjectName cmo = (ObjectName)wltree.pointer();
    Object mbs = wltree.getMBS();
    MBeanInfo mbinfo = WLScriptHelper.mbs_getMBeanInfo(mbs, cmo);
    MBeanOperationInfo[] opsinfo = mbinfo.getOperations();
    Map m0 = new HashMap();
    Map m2 = new HashMap();
    for(int i = 0; i < opsinfo.length; i++) {
      String opsname = opsinfo[i].getName();
      m0.put(opsname, opsinfo[i].getReturnType());
      MBeanParameterInfo[] params = opsinfo[i].getSignature();
      List l1 = new ArrayList();
      for(int j = 0; j < params.length; j++) {
        l1.add(params[j].getName() + "=" + params[j].getType());
      }
      m2.put(opsname, l1);
    }
    String[] headers = new String[]{"Name", "Return Type", "Args"};
    Object[] row = new Object[headers.length];
    OxyTable tabl = new OxyTable(headers);
    tabl.setMainIndex(1);
    tabl.setInternalObject(opsinfo);
    for(Iterator itr = m0.keySet().iterator(); itr.hasNext(); ) {
      String name = (String)itr.next();
      if(regex != null && !(StringUtils.matchSimpleRegex(name, regex))) {
        continue;
      }
      String returntype = (String)m0.get(name);
      Object args = m2.get(name);
      row[0] = name;
      row[1] = returntype;
      row[2] = args;
      tabl.addRow(row);      
    }
    //tabl.printTo(new PrintWriter(System.out));
    tabl.sort();
    return tabl;
  }

  public static OxyTable listmbs(WLFacadeContextHelper wlctx) throws Exception {
    Map m = wlctx.getConnection().getAllMBS();
    OxyTable tabl = OxyTable.parseFrom(m);
    tabl.setColumnIdentifiers(new String[]{"Key", "MBeanServer"});
    return tabl;
  }
  
}

